#include "spinlock.h"
#include "../../include/riscv.h"
#include "../boot/printf.h"

// 初始化锁
void initlock(spinlock *lk, char *name) {
  lk->locked = 0;
  lk->name = name;
  lk->cpu = 0;
  lk->count = 0;
}

// 获取锁
void acquire(spinlock *lk) {
  // 单核环境：关闭中断，防止中断处理程序获取同一个锁
  push_off();
  // 如果是重入（嵌套计数 > 0），直接增加计数并返回
  if(lk->count > 0) {
    lk->count++;
    return;
  }
  // 使用原子操作测试并设置锁
  // 如果locked已经是1，就一直循环等待
  while(__sync_lock_test_and_set(&lk->locked, 1) != 0) {
    // 忙等待
  }
  
  // 内存屏障，确保前面的操作完成
  __sync_synchronize();
  
  // 记录持有锁的CPU（单核永远是0）
  lk->cpu = r_tp();
  lk->count = 1;
}

// 释放锁
void release(spinlock *lk) {
  lk->count--;
   // 只有当嵌套计数为0时，才真正释放锁
   if(lk->count == 0) {
    // 清除持有锁的CPU记录
    lk->cpu = 0;
     // 内存屏障
  __sync_synchronize();
  
  // 原子释放锁
  __sync_lock_release(&lk->locked);
   }
 
  
  // 恢复中断状态
  pop_off();
}

// 检查是否持有锁
int holding(spinlock *lk) {
  return lk->locked;
}

// 中断嵌套计数器（单核简化版）
static int ncli = 0;           // 嵌套深度
static int intena = 0;          // 进入临界区前的中断状态

// 关闭中断并增加嵌套计数
void push_off(void) {
  int old = intr_get();
  intr_off();
  
  // 记录第一次进入时的中断状态
  if(ncli == 0) {
    intena = old;
  }
  ncli++;
}

// 减少嵌套计数，如果为0则恢复中断
void pop_off(void) {
  // 不允许中断状态
  if(intr_get()) {
    panic("pop_off - interruptible");
  }
  
  ncli--;
  
  // 嵌套计数不能为负
  if(ncli < 0) {
    panic("pop_off");
  }
  
  // 如果回到了最外层，恢复中断状态
  if(ncli == 0 && intena) {
    intr_on();
  }
}
